﻿//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using Microsoft.CodeAnalysis;
//using Microsoft.CodeAnalysis.CSharp;
//using Microsoft.CodeAnalysis.CSharp.Syntax;
//using Microsoft.CodeAnalysis.Text;
//using UIOC.Attributes;
//using UIOC.CodeAnalysis.Diagnostics;
//using UIOC.CodeAnalysis.Extensions;
//using UIOC.CodeAnalysis.Helpers;

//namespace UIOC.CodeAnalysis.Generators;

//internal static class ObjectGenerator {

//    private sealed class PropertyNotAllowSetterException : NotSupportedException {

//        public Location Location { get; set; }
//    }

//    private sealed class PropertyRequireGetterException : NotSupportedException {

//        public Location Location { get; set; }
//    }

//    private static void LogInfo(string message) {
//        SourceOutputHelper.LogInfoToSourceGenLog(DiagnosticSeverity.Info, $"[{nameof(ObjectGenerator)}] {message}");
//    }

//    public static void GenerateObject(
//        GeneratorExecutionContext context,
//        Compilation compilation,
//        UIOCReceiver receiver,
//        List<SyntaxTree> addedSyntaxTreeList
//    ) {
//        var autoImplementAttributeSymbol = compilation.GetTypeByMetadataName(AttributeFullNames.AutoImplement);
//        if (autoImplementAttributeSymbol == null) {
//            return;
//        }

//        var autoImplementFieldAttributeSymbol = compilation.GetTypeByMetadataName(AttributeFullNames.AutoImplementField);
//        if (autoImplementFieldAttributeSymbol == null) {
//            return;
//        }

//        var implementAttributeSymbol = compilation.GetTypeByMetadataName(AttributeFullNames.Implement);
//        if (implementAttributeSymbol == null) {
//            return;
//        }

//        var autowiredAttributeSymbol = compilation.GetTypeByMetadataName(AttributeFullNames.Autowired);
//        if (autowiredAttributeSymbol == null) {
//            return;
//        }

//        var fileFieldAttributeSymbol = compilation.GetTypeByMetadataName(AttributeFullNames.FileField);
//        if (fileFieldAttributeSymbol == null) {
//            return;
//        }

//        var objectInterfaceSymbol = compilation.GetTypeByMetadataName(TypeFullNames.IObjectInternal);
//        if (objectInterfaceSymbol == null) {
//            return;
//        }

//        var objectClassSymbol = compilation.GetTypeByMetadataName(TypeFullNames.Object);
//        if (objectClassSymbol == null) {
//            return;
//        }

//        LogInfo($"[Assembly({compilation.Assembly.Name})] {nameof(GenerateObject)} ...");

//        foreach (var interfaceDeclarationSyntax in receiver.CandidateInterfaces) {
//            var model = compilation.GetSemanticModel(interfaceDeclarationSyntax.SyntaxTree);
//            var interfaceSymbol = model.GetDeclaredSymbol(interfaceDeclarationSyntax);
//            if (interfaceSymbol != null) {
//                var autoImplementAttributeData = interfaceSymbol.GetAttributes()
//                    .FirstOrDefault(attr => attr.AttributeClass?.Equals(autoImplementAttributeSymbol, SymbolEqualityComparer.Default) == true);
//                if (autoImplementAttributeData == null) {
//                    continue;
//                }

//                var className = interfaceSymbol.GetClassNameFromInterface();

//                var baseTypeTypedConstant = autoImplementAttributeData.ConstructorArguments.Length > 0
//                    ? autoImplementAttributeData.ConstructorArguments[0]
//                    : autoImplementAttributeData.NamedArguments.FirstOrDefault(kv => kv.Key == nameof(AutoImplementAttribute.BaseType)).Value;

//                ITypeSymbol implementBaseTypeSymbol = null;
//                if (baseTypeTypedConstant.Kind == TypedConstantKind.Type
//                    && baseTypeTypedConstant.Value != null
//                    && baseTypeTypedConstant.Value is INamedTypeSymbol typeSymbol
//                ) {
//                    implementBaseTypeSymbol = typeSymbol;
//                } else {
//                    var classFullName = $"{interfaceSymbol.ContainingNamespace.GetFullNamespaceName()}.{className}";
//                    var classSymbol = compilation.GetTypeByMetadataName(classFullName);
//                    if (classSymbol != null && classSymbol.BaseType != null) {
//                        var systemObjectSymbol = compilation.GetSpecialType(SpecialType.System_Object);
//                        if (SymbolEqualityComparer.Default.Equals(classSymbol.BaseType, systemObjectSymbol)) {
//                            implementBaseTypeSymbol = objectClassSymbol;
//                        }
//                    } else {
//                        implementBaseTypeSymbol = objectClassSymbol;
//                    }
//                }
//                try {
//                    var (compilationUnitSyntax, namespaceName) = GenerateImplementationCompilationUnit(
//                        interfaceSymbol,
//                        className,
//                        implementBaseTypeSymbol,
//                        implementAttributeSymbol,
//                        objectInterfaceSymbol,
//                        autoImplementFieldAttributeSymbol,
//                        autowiredAttributeSymbol,
//                        fileFieldAttributeSymbol
//                    );
//                    var outputSource = SourceText.From(compilationUnitSyntax.NormalizeWhitespace().ToFullString(), Encoding.UTF8);
//                    var syntaxTree = CSharpSyntaxTree.ParseText(outputSource, context.ParseOptions as CSharpParseOptions);
//                    var interfaceName = interfaceSymbol.GetShortName().Replace("<", "(").Replace(">",")");
//                    var classFileName = interfaceName.StartsWith("I") && interfaceName.Length > 1 ? interfaceName.Substring(1) : interfaceName;
//                    var (fullFilePath, filePath, fileNameOnly) = interfaceDeclarationSyntax.SyntaxTree.GetGeneratedSourceFilePath(
//                        compilation.Assembly.Name,
//                        namespaceName,
//                        nameof(ObjectGenerator),
//                        hintName: classFileName
//                    );
//                    syntaxTree = syntaxTree.WithFilePath(fullFilePath);
//                    context.AddSource(filePath.Replace(".g.cs", string.Empty).Replace("/", "__").Replace('.', '_') + ".g.cs", outputSource);
//                    addedSyntaxTreeList.Add(syntaxTree);
//                    LogInfo($"[File({fileNameOnly})] ...\n{string.Join("\n", outputSource.Lines)}");
//                    SourceOutputHelper.OutputSourceToFile(fullFilePath, outputSource.ToString);
//                } catch (PropertyNotAllowSetterException e) {
//                    context.ReportDiagnostic(Diagnostic.Create(AutoImplementFieldNotAllowSetterDiagnostic.Rule, e.Location, interfaceSymbol.Name));
//                } catch (PropertyRequireGetterException e) {
//                    context.ReportDiagnostic(Diagnostic.Create(AutoImplementFieldRequireGetterDiagnostic.Rule, e.Location, interfaceSymbol.Name));
//                }
//            }
//        }
//    }

//    private static (CompilationUnitSyntax CompilationUnitSyntax, string NamespaceName) GenerateImplementationCompilationUnit(
//        INamedTypeSymbol interfaceSymbol,
//        string className,
//        ITypeSymbol implementBaseTypeSymbol,
//        INamedTypeSymbol implementAttributeSymbol,
//        INamedTypeSymbol objectInterfaceSymbol,
//        INamedTypeSymbol autoImplementFieldAttributeSymbol,
//        INamedTypeSymbol autowiredAttributeSymbol,
//        INamedTypeSymbol fileFieldAttributeSymbol
//    ) {
//        var modifierSyntaxKind = interfaceSymbol.DeclaredAccessibility.ToSyntaxKind();
//        var modifierSyntaxTokens = new SyntaxToken[modifierSyntaxKind == null ? 2 : 3];
//        modifierSyntaxTokens[modifierSyntaxTokens.Length - 2] = SyntaxFactory.Token(SyntaxKind.AbstractKeyword);
//        modifierSyntaxTokens[modifierSyntaxTokens.Length - 1] = SyntaxFactory.Token(SyntaxKind.PartialKeyword);
//        if (modifierSyntaxKind != null) {
//            modifierSyntaxTokens[0] = SyntaxFactory.Token(modifierSyntaxKind.Value);
//        }

//        var baseTypeSyntaxList = new List<SimpleBaseTypeSyntax> {
//            interfaceSymbol.CreateSimpleBaseTypeSyntax(),
//        };

//        if (implementBaseTypeSymbol != null) {
//            baseTypeSyntaxList.Insert(0, implementBaseTypeSymbol.CreateSimpleBaseTypeSyntax());
//        }

//        var objectInterfaceTypeSyntax = objectInterfaceSymbol.CreateSimpleBaseTypeSyntax();

//        baseTypeSyntaxList.Add(objectInterfaceTypeSyntax);

//        var classDeclarationSyntax = SyntaxFactory.ClassDeclaration(className)
//            .AddModifiers(modifierSyntaxTokens)
//            .AddAttributeLists(
//                SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList([
//                    GenerateImplementAttribute(implementAttributeSymbol,interfaceSymbol)
//                ]))
//            )
//            .AddBaseListTypes([.. baseTypeSyntaxList])
//            .AddConstraintClauses([.. interfaceSymbol.GetConstraintClauses()]);

//        // 添加成员
//        var memberDeclarationSyntaxList = new List<MemberDeclarationSyntax>();
//        foreach (var memberSymbol in interfaceSymbol.GetMembers()) {
//            switch (memberSymbol) {
//                case IPropertySymbol propertySymbol:
//                    var (propertyDeclarationSyntax, fieldDeclarationSyntax) = GeneratePropertyImplementation(
//                        propertySymbol,
//                        autoImplementFieldAttributeSymbol,
//                        autowiredAttributeSymbol,
//                        fileFieldAttributeSymbol
//                    );
//                    if (fieldDeclarationSyntax != null) {
//                        memberDeclarationSyntaxList.Add(fieldDeclarationSyntax);
//                    }
//                    if (propertyDeclarationSyntax != null) {
//                        memberDeclarationSyntaxList.Add(propertyDeclarationSyntax);
//                    }
//                    break;
//            }
//        }

//        classDeclarationSyntax = classDeclarationSyntax.AddMembers([.. memberDeclarationSyntaxList]);

//        var leadingTriviaSyntax = SyntaxFactory.Comment($"// <auto-generated> This file was automatically generated by {nameof(UIOCGenerator)}. </auto-generated>");
//        if (interfaceSymbol.ContainingNamespace.IsGlobalNamespace) {
//            // 全局命名空间
//            classDeclarationSyntax = classDeclarationSyntax.WithLeadingTrivia(leadingTriviaSyntax, SyntaxFactory.CarriageReturnLineFeed);
//            return (SyntaxFactory.CompilationUnit().AddMembers(classDeclarationSyntax), null);
//        } else {
//            // 非全局命名空间
//            var namespaceName = interfaceSymbol.ContainingNamespace.GetFullNamespaceName();
//            var namespaceDeclarationSyntax = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.IdentifierName(namespaceName))
//                .WithLeadingTrivia(leadingTriviaSyntax, SyntaxFactory.CarriageReturnLineFeed)
//                .WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed);
//            namespaceDeclarationSyntax = namespaceDeclarationSyntax.AddMembers(classDeclarationSyntax);
//            return (SyntaxFactory.CompilationUnit().AddMembers(namespaceDeclarationSyntax), namespaceName);
//        }
//    }

//    // 生成 [global::UIOC.Attributes.Implement(typeof(global::{{NameSpace}}.{{IInterface}}))] 特性
//    private static AttributeSyntax GenerateImplementAttribute(INamedTypeSymbol implementAttributeSymbol, INamedTypeSymbol interfaceSymbol) {
//        var typeOfExpressionSyntax = SyntaxFactory.TypeOfExpression(
//            SyntaxFactory.ParseTypeName(interfaceSymbol.CreateSimpleNameSyntax(IsUnboundGenericType: true).ToString())
//        );
//        return SyntaxFactory.Attribute(implementAttributeSymbol.CreateSimpleNameSyntax())
//            .AddArgumentListArguments(SyntaxFactory.AttributeArgument(typeOfExpressionSyntax));
//    }

//    private static (PropertyDeclarationSyntax, FieldDeclarationSyntax) GeneratePropertyImplementation(
//        IPropertySymbol propertySymbol,
//        INamedTypeSymbol autoImplementFieldAttributeSymbol,
//        INamedTypeSymbol autowiredAttributeSymbol,
//        INamedTypeSymbol fileFieldAttributeSymbol
//    ) {
//        var autoImplementFieldAttributeData = propertySymbol.GetAttributes()
//            .FirstOrDefault(attr => attr.AttributeClass?.Equals(autoImplementFieldAttributeSymbol, SymbolEqualityComparer.Default) == true);
//        if (autoImplementFieldAttributeData == null) {
//            return (null, null);
//        }

//        var fieldTypeTypedConstant = autoImplementFieldAttributeData.ConstructorArguments.Length > 0
//            ? autoImplementFieldAttributeData.ConstructorArguments[0]
//            : autoImplementFieldAttributeData.NamedArguments.FirstOrDefault(kv => kv.Key == nameof(AutoImplementFieldAttribute.FieldType)).Value;

//        ITypeSymbol fieldTypeSymbol = null;
//        if (fieldTypeTypedConstant.Kind == TypedConstantKind.Type
//            && fieldTypeTypedConstant.Value != null
//            && fieldTypeTypedConstant.Value is ITypeSymbol typeSymbol
//        ) {
//            fieldTypeSymbol = typeSymbol;
//        } else {
//            fieldTypeSymbol = propertySymbol.Type;
//        }

//        var autowiredAttributeListSyntax = SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList([
//            SyntaxFactory.Attribute(autowiredAttributeSymbol.CreateSimpleNameSyntax())
//        ]));
//        var fileFieldAttributeListSyntax = SyntaxFactory.AttributeList(SyntaxFactory.SeparatedList([
//            SyntaxFactory.Attribute(fileFieldAttributeSymbol.CreateSimpleNameSyntax())
//        ]));

//        var fieldName = $"field__{propertySymbol.Name}__";
//        var variableTypeNameSyntax = fieldTypeSymbol.CreateSimpleNameSyntax();
//        var variableDeclaratorSyntax = SyntaxFactory.VariableDeclarator(fieldName);
//        var variableDeclarationSyntax = SyntaxFactory.VariableDeclaration(variableTypeNameSyntax)
//            .AddVariables(variableDeclaratorSyntax);

//        var fieldDeclarationSyntax = SyntaxFactory.FieldDeclaration(variableDeclarationSyntax)
//            .AddModifiers(SyntaxFactory.Token(SyntaxKind.PrivateKeyword))
//            .AddAttributeLists(autowiredAttributeListSyntax, fileFieldAttributeListSyntax);

//        var propertyTypeNameSyntax = propertySymbol.Type.CreateSimpleNameSyntax();
//        var propertyDeclarationSyntax = SyntaxFactory.PropertyDeclaration(
//            propertyTypeNameSyntax,
//            propertySymbol.Name
//        ).AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword));

//        if (propertySymbol.GetMethod == null) {
//            throw new PropertyRequireGetterException { Location = propertySymbol.Locations[0] };
//        }
//        if (propertySymbol.SetMethod != null) {
//            throw new PropertyNotAllowSetterException { Location = propertySymbol.SetMethod.Locations[0] };
//        }

//        var accessor = SyntaxFactory.AccessorDeclaration(
//            SyntaxKind.GetAccessorDeclaration
//        ).WithExpressionBody(SyntaxFactory.ArrowExpressionClause(
//            SyntaxFactory.IdentifierName(fieldName)
//        ))
//        .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));

//        propertyDeclarationSyntax = propertyDeclarationSyntax.AddAccessorListAccessors(accessor);
//        return (propertyDeclarationSyntax, fieldDeclarationSyntax);
//    }
//}
